﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace iNet
{
	/// <summary>
	/// 表示有上下限的值。
	/// </summary>
	/// <typeparam name="T">值的型別。</typeparam>
	public struct BoundedValue<T>
	{
		#region 欄位
		IComparer<T> _Comparer;
		T _Maximum;
		T _Minimum;
		T _Value;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化 BoundedValue 結構。
		/// </summary>
		/// <param name="minimum">下限值。</param>
		/// <param name="maximum">上限值。</param>
		/// <param name="value">初始值。</param>
		/// <exception cref="ArgumentException">minimum 大於 maximum。</exception>
		/// <exception cref="ArgumentNullException">型別 T 沒有實作 IComparable&lt;T&gt; 介面。</exception>
		public BoundedValue(T minimum, T maximum, T value)
			: this(minimum, maximum, value, null)
		{ }
		/// <summary>
		/// 初始化 BoundedValue 結構。，並將值初始化為下限值。
		/// </summary>
		/// <param name="minimum">下限值。</param>
		/// <param name="maximum">上限值。</param>
		/// <exception cref="ArgumentException">minimum 大於 maximum。</exception>
		/// <exception cref="ArgumentNullException">型別 T 沒有實作 IComparable&lt;T&gt; 介面。</exception>
		public BoundedValue(T minimum, T maximum)
			: this(minimum, maximum, minimum, null)
		{ }
		/// <summary>
		/// 初始化 BoundedValue 結構，並將值初始化為下限值。
		/// </summary>
		/// <param name="minimum">下限值。</param>
		/// <param name="maximum">上限值。</param>
		/// <param name="comparer">提供值大小比較的 IComparer&lt;T&gt; 介面。</param>
		/// <exception cref="ArgumentException">minimum 大於 maximum。</exception>
		/// <exception cref="ArgumentNullException">型別 T 沒有實作 IComparable&lt;T&gt; 介面，且 comparer 為 Null (Visual Basic 為 Nothing)。</exception>
		public BoundedValue(T minimum, T maximum, IComparer<T> comparer)
			: this(minimum, maximum, minimum, comparer)
		{ }
		/// <summary>
		/// 初始化 BoundedValue 結構。
		/// </summary>
		/// <param name="minimum">下限值。</param>
		/// <param name="maximum">上限值。</param>
		/// <param name="value">初始值。</param>
		/// <param name="comparer">提供值大小比較的 IComparer&lt;T&gt; 介面。</param>
		/// <exception cref="ArgumentException">minimum 大於 maximum。</exception>
		/// <exception cref="ArgumentNullException">型別 T 沒有實作 IComparable&lt;T&gt; 介面，且 comparer 為 Null (Visual Basic 為 Nothing)。</exception>
		public BoundedValue(T minimum, T maximum, T value, IComparer<T> comparer)
		{
			//確認參數
			if (comparer == null && !typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
				throw new ArgumentNullException("comparer");

			//初始化
			_Comparer = comparer;
			_Minimum = minimum;
			_Maximum = maximum;
			_Value = default(T);

			//確認上下限
			if (this.Compare(minimum, maximum) > 0)
				throw new ArgumentException();

			//初始化值
			if (this.Compare(value, minimum) <= 0)
				_Value = minimum;
			else if (this.Compare(value, maximum) >= 0)
				_Value = maximum;
			else
				_Value = value;
		}
		#endregion
		#region Compare
		int Compare(T x, T y)
		{
			if (_Comparer != null)
				return _Comparer.Compare(x, y);
			if (x is IComparable<T>)
				return (x as IComparable<T>).CompareTo(y);
			if (y is IComparable<T>)
				return -(y as IComparable<T>).CompareTo(x);
			if (!object.ReferenceEquals(x, null) || !object.ReferenceEquals(y, null))
				throw new InvalidOperationException();
			return 0;
		}
		#endregion
		#region Comparer
		/// <summary>
		/// 取得提供值大小比較的 IComparer&lt;T&gt; 介面。
		/// </summary>
		public IComparer<T> Comparer
		{
			get
			{
				return _Comparer;
			}
		}
		#endregion
		#region Equals
		/// <summary>
		/// 和指定的物件比較是否相等。
		/// </summary>
		/// <param name="obj">指定的物件。</param>
		/// <returns>True 表示相等，False 表示不相等。</returns>
		public override bool Equals(object obj)
		{
			if (obj is BoundedValue<T>)
				return this.Equals((BoundedValue<T>)obj);
			return false;
		}
		/// <summary>
		/// 和指定的 BoundedValue&lt;T&gt; 比較值是否相等。
		/// </summary>
		/// <param name="value">指定的 BoundedValue&lt;T&gt;。</param>
		/// <returns>True 表示值相等，False 表示不相等。</returns>
		public bool Equals(BoundedValue<T> value)
		{
			return (this == value);
		}
		#endregion
		#region GetHashCode
		/// <summary>
		/// 取得雜湊值。
		/// </summary>
		/// <returns>雜湊值。</returns>
		public override int GetHashCode()
		{
			return _Value.GetHashCode();
		}
		#endregion
		#region implicit operator
		public static implicit operator T(BoundedValue<T> value)
		{
			return value._Value;
		}
		#endregion
		#region Maximum
		/// <summary>
		/// 取得上限值。
		/// </summary>
		public T Maximum
		{
			get
			{
				return _Maximum;
			}
		}
		#endregion
		#region Minimum
		/// <summary>
		/// 取得下限值。
		/// </summary>
		public T Minimum
		{
			get
			{
				return _Minimum;
			}
		}
		#endregion
		#region operator ==
		public static bool operator ==(BoundedValue<T> x, BoundedValue<T> y)
		{
			T valueX = x._Value;
			T valueY = y._Value;
			if (!object.ReferenceEquals(valueX, null))
				return valueX.Equals(valueY);
			if (!object.ReferenceEquals(valueY, null))
				return valueY.Equals(valueX);
			return true;
		}
		#endregion
		#region operator !=
		public static bool operator !=(BoundedValue<T> x, BoundedValue<T> y)
		{
			T valueX = x._Value;
			T valueY = y._Value;
			if (!object.ReferenceEquals(valueX, null))
				return !valueX.Equals(valueY);
			if (!object.ReferenceEquals(valueY, null))
				return !valueY.Equals(valueX);
			return false;
		}
		#endregion
		#region ToString
		/// <summary>
		/// 將值轉成對應的字串表示。
		/// </summary>
		/// <returns>對應的字串表示。</returns>
		public override string ToString()
		{
			if (!object.ReferenceEquals(_Value, null))
				return _Value.ToString();
			return "null";
		}
		#endregion
		#region Value
		/// <summary>
		/// 取得或設定值，若值小於下限值則會調整至下限值；若值大於上限值則會調整至上限值。
		/// </summary>
		public T Value
		{
			get
			{
				return _Value;
			}
			set
			{
				if (this.Compare(value, _Minimum) <= 0)
					_Value = _Minimum;
				else if (this.Compare(value, _Maximum) >= 0)
					_Value = _Maximum;
				else
					_Value = value;
			}
		}
		#endregion
	}
}
